package eventplanner.ejb.dao;

import eventplanner.ejb.Session;
import eventplanner.ejb.adders.GroupAdder;
import eventplanner.ejb.adders.TagsAdder;
import eventplanner.ejb.exceptions.UnauthorizedException;
import eventplanner.entities.Event;
import eventplanner.entities.Feed;
import eventplanner.entities.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * This EJB class (@Stateless) provides methods for db interaction regarding Tokens.
 *
 * @see Token
 */
@Stateless
public class TokenDao {

	private static final Logger LOG = LoggerFactory.getLogger(TokenDao.class);

	@PersistenceContext
	private EntityManager em;

	@EJB
	private TagsAdder tagsAdder;

	@EJB
	private GroupAdder groupAdder;

	@Inject
	private Session session;

	public Token find(long tokenId) {
		Token token = em.find(Token.class, tokenId);

		LOG.info("Session {}", session);
		LOG.info("Session user {}", session.getUser());
		LOG.info("Token {}", token);
		LOG.info("Token user {}", token.getUser());
		if (token != null && !session.getUser().equals(token.getUser())) {
			throw new UnauthorizedException();
		}
		return token;
	}

	public List<Event> getEventsForToken(String tokenString) {
		Token token = getTokenOrNull(tokenString);

		if (token == null) {
			LOG.warn("Unknown tokenString or unauthenticated token usage attempt for tokenString '{}'", tokenString);
			return Collections.emptyList();
		}

		Set<Feed> feeds = token.getFeeds();
		Set<String> tags = token.getTags();
		Set<String> organizers = token.getOrganizers();
		Set<String> targets = token.getTargets();

		List<Event> events = tagsAdder.readWithTags(tags);
		List<Event> allEvents = new ArrayList<>(events);
		allEvents.addAll(groupAdder.getEventsWithOrganizer(organizers));
		allEvents.addAll(groupAdder.getEventsWithTarget(targets));

		for (Feed feed : feeds) {
			allEvents.addAll(feed.getEvents());
		}

		return allEvents;
	}

	private Token getTokenOrNull(String tokenString) {
		TypedQuery<Token> query = em.createQuery("select t from Token t where t.tokenString = ?1", Token.class);
		query.setParameter(1, tokenString);

		try {
			return query.getSingleResult();
		} catch (NoResultException nre) {
			return null;
		}
	}
}
